//    Copyright (C) Kherty.  All rights reserved.
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using OpenLS.Core.Serialization;
using System;
using System.Collections.ObjectModel;

namespace OpenLS.Drawing
{
    public class GradientFillProperties : LineFillProperties
    {
        private const bool defaultrotWithShape = false;
        private RelativeRectangle _tileRect;
        private readonly ObservableCollection<GradientStop> _gradientStops = new ObservableCollection<GradientStop>();
        private bool rotWithShape = defaultrotWithShape;
        private ShadeProperties shadeProperties;
        private TileFlipMode tileFlipMode;

        public TileFlipMode TileFlipMode
        {
            get { return tileFlipMode; }
            set { tileFlipMode = value; NotifyPropertyChanged("TileFlipMode"); }
        }

        public bool RotateWithShape
        {
            get { return rotWithShape; }
            set { rotWithShape = value; NotifyPropertyChanged("RotateWithShape");}
        }

        public ObservableCollection<GradientStop> GradientStops
        {
            get { return _gradientStops; }
        }

        public ShadeProperties ShadeProperties
        {
            get { return shadeProperties; }
            set { shadeProperties = value; NotifyPropertyChanged("ShadeProperties");}
        }

        public RelativeRectangle TileRectangle
        {
            get { return _tileRect; }
            set { _tileRect = value; NotifyPropertyChanged("TileRectangle");}
        }


        internal override Brush ToBrush(ColorScheme colorScheme)
        {
            if (ShadeProperties is LinearShadeProperties)
            {
                var ls = (LinearShadeProperties) ShadeProperties;
                double angle = ls.Angle;
                angle = -angle / 180 * Math.PI;
                var result = new LinearGradientBrush(GetGradientStops(colorScheme))
                                 {
                                     StartPoint = new Point(0.5 - 0.5*Math.Cos(angle), 0.5 + 0.5*Math.Sin(angle)),
                                     EndPoint = new Point(0.5 + 0.5*Math.Cos(angle), 0.5 - 0.5*Math.Sin(angle))
                                 };
                result.Freeze();
                return result;

            }
            if (ShadeProperties is PathShadeProperties)
            {
                var p = (PathShadeProperties)ShadeProperties;
                switch (p.Path)
                {
                    case PathShadeType.Circle:
                        {
                            var result = new RadialGradientBrush(GetGradientStops(colorScheme));
                        return result;
                        }
                case PathShadeType.Rectangle:
                        {
                            var result = new DrawingBrush {Viewport = new Rect(0, 0, 1, 1)};
                            // result.ViewportUnits = BrushMappingMode.Absolute;
                            var gr = new DrawingGroup();
                            
                            result.Drawing = gr;
                            gr.Children.Add(new GeometryDrawing(Brushes.Transparent, null, new RectangleGeometry(new Rect(0, 0, 1, 1))));
                            gr.Children.Add(GetPathDrawing(colorScheme, new Point(1, 0), new Point(0, 0), new Point(0, 0), new Point(0.5, 0.5), new Point(0, 1)));
                            gr.Children.Add(GetPathDrawing(colorScheme, new Point(0, 1), new Point(0, 0), new Point(0, 0), new Point(0.5, 0.5), new Point(1, 0)));
                            gr.Children.Add(GetPathDrawing(colorScheme, new Point(0, 0), new Point(1, 0), new Point(1, 0), new Point(0.5, 0.5), new Point(1, 1)));
                            gr.Children.Add(GetPathDrawing(colorScheme, new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(0.5, 0.5), new Point(0, 1)));

                            return result;
                        }
                    default:
                        throw new NotSupportedException();
                }
            }
                return new LinearGradientBrush(GetGradientStops(colorScheme));
        }
        GeometryDrawing  GetPathDrawing(ColorScheme colorScheme, Point startPoint, Point endPoint, Point sp, params Point[] points)
        {
            var segments = new List<PathSegment>();
            foreach (Point p in points)
                segments.Add(new LineSegment(p, false));
            var pathFigure = new PathFigure(sp, segments, false);
            var pathGeometry = new PathGeometry(new[]{pathFigure});

            return new GeometryDrawing(
                new LinearGradientBrush(GetGradientStops(colorScheme)) {StartPoint = startPoint, EndPoint = endPoint},
                null, pathGeometry);
        }

        GradientStopCollection GetGradientStops(ColorScheme colorScheme)
        {
            var result = new GradientStopCollection();
            foreach (GradientStop stop in GradientStops)
                result.Add(stop.ToGradientStop(colorScheme));
            return result;
        }


        internal override void ReadXmlCore(ReadContext context)
        {
            using (var c = context.Read("gradFill"))
            {
                TileFlipMode = c.GetOptionalEnum("flip", TileFlipMode.None);
                RotateWithShape = c.GetOptionalBoolean("rotWithShape", defaultrotWithShape);
                GradientStops.Clear();
                foreach (var stop in c.ReadOptionalListElement<GradientStop>("gsLst", "gs"))
                {
                    GradientStops.Add(stop);
                }
               // GradientStops = c.ReadOptionalListElement<GradientStop>("gsLst", "gs");
                ReadContext ccc = c;
                ShadeProperties = ShadeProperties.ReadShapeProperties(ccc);
                TileRectangle = c.ReadOptionalElementAs<RelativeRectangle>("tileRect");
            }
        }

        internal override void WriteXmlCore(WriteContext context)
        {
            using (WriteContext c = context.Write("gradFill"))
            {
                c.SetOptionalEnum("flip", TileFlipMode, TileFlipMode.None);
                c.SetOptionalBoolean("rotWithShape", RotateWithShape, defaultrotWithShape);
                c.WriteOptionalElementList(_gradientStops, "gsLst");
                c.WriteOptionalElement(ShadeProperties);
                c.WriteOptionalElementAs(TileRectangle, "tileRect");
            }
        }
    }
}